#ifndef THREAD_H
#define THREAD_H

#include <etl/vector.h>
#include <functional>
#include <utility>
#include <cmsis_os.h>
#include <core.h>

namespace os {
/**
 * @brief 用户注册线程表
 */
struct TaskLists {
    TaskHandle_t ptr;
    TaskLists* next;
};

class Thread {
public:
    using ThreadFnType = std::function<void(void*)>;

    /**
     * @brief 动态创建线程
     * @param entry 线程入口
     * @param name 线程名
     * @param stkSize 线程栈大小
     * @param param 线程入参
     * @param priority 线程优先级
     */
    Thread(ThreadFnType entry, char const* name, uint16_t const stkSize, void* param, uint32_t const priority)
        : fn_(std::move(entry)), inputParam_(param) {
        threadName_ = new char[strlen(name) + 1];
        memcpy(threadName_, name, strlen(name) + 1);

        xTaskCreate(thread_type_wrapper, threadName_, stkSize, this, priority, &hThread_);

        os_assert(hThread_ != nullptr, "Creat Thread Failed");
    }

    /**
     * @brief 静态创建线程
     * @param entry 线程入口
     * @param name 线程名
     * @param stkSize 线程栈大小
     * @param param 线程入参
     * @param priority 线程优先级
     * @param stck 线程栈
     * @param tcb 线程控制块
     */
    Thread(ThreadFnType entry, char const* name, uint32_t const stkSize, void* param, uint32_t const priority,
           uint32_t stck[], StaticTask_t* tcb)
        : fn_(std::move(entry)), inputParam_(param) {
        threadName_ = new char[strlen(name) + 1];
        memcpy(threadName_, name, strlen(name) + 1);

        os_assert(stck != nullptr && tcb != nullptr, "");

        hThread_ = xTaskCreateStatic(thread_type_wrapper, threadName_, stkSize, this, priority, stck, tcb);
        vTaskSuspend(hThread_);  // 挂起线程，初始化结束后统一启动
        taskLists_push_back(hThread_);
        os_assert(hThread_ != nullptr, "Creat Thread Failed");
    }

    ~Thread() {
        vTaskDelete(hThread_);
        delete threadName_;
    }

    [[nodiscard]] TaskHandle_t get_hThread() const { return hThread_; }

private:
    // HAL库型线程句柄
    TaskHandle_t hThread_{};
    // 任务函数
    ThreadFnType const fn_;
    void* inputParam_;
    char* threadName_;

    static void taskLists_push_back(TaskHandle_t const& task);

    static void thread_type_wrapper(void* p) {
        if (p == nullptr) return;
        auto const hThread_ = static_cast<Thread*>(p);
        hThread_->fn_(hThread_->inputParam_);
    }
};

/**
 * @brief 动态创建线程
 * @param size 线程栈大小
 * @param param 线程入参
 * @param priority 线程优先级
 * @param entry 线程入口
 * @return 线程句柄
 */
Thread* createThread(uint16_t size, void* param, uint32_t priority, Thread::ThreadFnType const& entry);
/* -------------------------------------------- */
}  // namespace os

/**
 * @brief 静态注册线程
 * @param name 线程对象名
 * @param stkSize 线程栈大小
 * @param param 线程入参
 * @param priority 线程优先级
 */
#define CREATE_THREAD_STATIC(name, stkSize, param, priority)                                                 \
    [[noreturn]] void ThreadFn_##name(void*);                                                                \
    char name##_thread_name__[] = #name;                                                                     \
    uint32_t name##_thread_stack__[stkSize] = {0};                                                           \
    StaticTask_t name##_tcb__;                                                                               \
    os::Thread::ThreadFnType fnPkg_##name(ThreadFn_##name);                                                  \
    os::Thread name{                                                                                         \
        fnPkg_##name, name##_thread_name__, stkSize, param, priority, name##_thread_stack__, &name##_tcb__}; \
    void ThreadFn_##name(void*)
/* --------------------------------------------------- */

#endif  // THREAD_H